package leetcode.editor.cn;
//给你一个字符串 s ，请你去除字符串中重复的字母，使得每个字母只出现一次。需保证 返回结果的字典序最小（要求不能打乱其他字符的相对位置）。 
//
// 
//
// 示例 1： 
//
// 
//输入：s = "bcabc"
//输出："abc"
// 
//
// 示例 2： 
//
// 
//输入：s = "cbacdcbc"
//输出："acdb" 
//
// 
//
// 提示： 
//
// 
// 1 <= s.length <= 104 
// s 由小写英文字母组成 
// 
//
// 
//
// 注意：该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct
//-characters 相同 
// Related Topics 栈 贪心 字符串 单调栈 
// 👍 914 👎 0


import java.util.Stack;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution74 {

    /**
     * 去重
     * 如果输入s = "bcabc"，这个算法会返回"bca"
     *
     * @param s
     * @return
     */
    public String removeDuplicateLetters1(String s) {
        // ascii码个数
        boolean[] inStack = new boolean[256];
        Stack<Character> stack = new Stack<>();

        for (char c : s.toCharArray()) {
            if (inStack[c]) {
                continue;
            }
            inStack[c] = true;
            stack.push(c);
        }
        StringBuilder stringBuilder = new StringBuilder();
        while (!stack.isEmpty()) {
            stringBuilder.append(stack.pop());
        }
        return stringBuilder.reverse().toString();
    }

    /**
     * 去重+字典值大小
     * <p>
     * 对于输入s = "bcabc"，我们可以得出正确结果"abc"了
     * 假设s = "bcac"，按照刚才的算法逻辑，返回的结果是"ac"，而正确答案应该是"bac"
     *
     * @param s
     * @return
     */
    public String removeDuplicateLetters2(String s) {
        // ascii码个数
        boolean[] inStack = new boolean[256];
        Stack<Character> stack = new Stack<>();

        for (char c : s.toCharArray()) {
            // 把前面大的值都删掉
            while (inStack[c] && stack.peek() > c) {
                inStack[stack.pop()] = false;
            }
            inStack[c] = true;
            stack.push(c);
        }
        StringBuilder stringBuilder = new StringBuilder();
        while (!stack.isEmpty()) {
            stringBuilder.append(stack.pop());
        }
        return stringBuilder.reverse().toString();
    }

    /**
     * 去重+字典值大小+计数
     * <p>
     * 对于输入s = "bcabc"，我们可以得出正确结果"abc"了
     * 假设s = "bcac"，按照刚才的算法逻辑，返回的结果是"bac"
     *
     * @param s
     * @return
     */
    public static String removeDuplicateLetters3(String s) {
        // ascii码个数
        boolean[] inStack = new boolean[256];
        int[] count = new int[256];
        Stack<Character> stack = new Stack<>();

        for (int i = 0; i < s.length(); i++) {
            count[s.charAt(i)]++;
        }

        for (char c : s.toCharArray()) {
            // 每遍历过一个字符，都将对应的计数减一
            count[c]--;

            if (inStack[c]) continue;

            while (!stack.isEmpty() && stack.peek() > c) {
                // 若之后不存在栈顶元素了，则停止 pop
                if (count[stack.peek()] == 0) {
                    break;
                }
                // 若之后还有，则可以 pop
                inStack[stack.pop()] = false;
            }
            stack.push(c);
            inStack[c] = true;
        }
        StringBuilder stringBuilder = new StringBuilder();
        while (!stack.isEmpty()) {
            stringBuilder.append(stack.pop());
        }
        return stringBuilder.reverse().toString();
    }

    public static void main(String[] args) {
        System.out.println(removeDuplicateLetters3("fsadasfdasasd"));
    }
}
//leetcode submit region end(Prohibit modification and deletion)
